// SetStateDemo.tsx
import React, { useState, useEffect } from "react";

/**
 * 演示 React 中 setState 的核心特性与常见陷阱
 *
 * 特性：
 * - 状态不可变（immutable）
 * - 异步更新（出于性能优化）
 * - 批量合并（React 18+ 自动批处理）
 *
 * 常见问题：
 * - 闭包中 state 过期（stale closure）
 * - 连续 setState 不按预期累加
 * - 在循环或高频事件中丢失更新
 */

export default function SetStateDemo() {
  return (
    <div style={{ padding: "20px", fontFamily: "sans-serif" }}>
      <h2>useState / setState 演示</h2>
      <p>查看控制台日志，理解 setState 的行为</p>

      <hr />
      <BasicUsage />
      <hr />
      <AsyncBatchingDemo />
      <hr />
      <StaleClosureDemo />
      <hr />
      <LoopUpdateDemo />
    </div>
  );
}

// =============== 1. 基础用法 ===============
function BasicUsage() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h3>✅ 基础用法</h3>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1（可能有问题）</button>
      <button onClick={() => setCount((c) => c + 1)}>
        +1（推荐：函数式更新）
      </button>
    </div>
  );
}

// =============== 2. 异步与批量更新 ===============
function AsyncBatchingDemo() {
  const [a, setA] = useState(0);
  const [b, setB] = useState(0);

  const handleBatchUpdate = () => {
    // React 18+：即使在异步回调中也会自动批处理（需使用 createRoot）
    setTimeout(() => {
      setA(a + 1);
      setB(b + 1);
      console.log(
        "在 setTimeout 中调用 setState 后，a 和 b 应该只 re-render 一次"
      );
    }, 0);
  };

  useEffect(() => {
    console.log("AsyncBatchingDemo re-rendered: a=", a, ", b=", b);
  });

  return (
    <div>
      <h3>🔄 异步与批量更新（React 18+ 自动批处理）</h3>
      <p>
        a: {a}, b: {b}
      </p>
      <button onClick={handleBatchUpdate}>批量更新 a 和 b</button>
      <p>✅ 控制台应只打印一次 re-render 日志（说明被 batched）</p>
    </div>
  );
}

// =============== 3. 闭包过期（Stale Closure） ===============
function StaleClosureDemo() {
  const [count, setCount] = useState(0);

  const handleClickBad = () => {
    // 问题：连续快速点击时，多个回调捕获的是同一个旧 count
    setTimeout(() => {
      setCount(count + 1); // ❌ 使用过期的 count
    }, 100);
  };

  const handleClickGood = () => {
    setTimeout(() => {
      setCount((c) => c + 1); // ✅ 使用函数式更新，总是基于最新值
    }, 100);
  };

  return (
    <div>
      <h3>⚠️ 闭包过期（Stale Closure）</h3>
      <p>Count: {count}</p>
      <button onClick={handleClickBad}>+1（错误：使用闭包中的 count）</button>
      <button onClick={handleClickGood}>+1（正确：使用函数式更新）</button>
      <p>👉 快速点击“错误”按钮多次，只会 +1 一次！</p>
    </div>
  );
}

// =============== 4. 循环/高频更新丢失 ===============
function LoopUpdateDemo() {
  const [count, setCount] = useState(0);

  const handleAdd10Bad = () => {
    // ❌ 错误：所有 setCount 都基于初始 count=0
    for (let i = 0; i < 10; i++) {
      setCount(count + 1);
    }
  };

  const handleAdd10Good = () => {
    // ✅ 正确：每次基于最新值
    for (let i = 0; i < 10; i++) {
      setCount((c) => c + 1);
    }
  };

  return (
    <div>
      <h3>🔥 循环中更新状态（高频调用）</h3>
      <p>Count: {count}</p>
      <button onClick={handleAdd10Bad}>+10（错误：只加 1）</button>
      <button onClick={handleAdd10Good}>+10（正确：加 10）</button>
    </div>
  );
}
